﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Linq;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.IO;
using USB2XXX;

/**
 * 注意：若运行程序提示找不到USB2XXX.dll文件，可以将工程目录下的USB2XXX.dll和libusb-1.0.dll文件拷贝到exe程序输出目录下即可（一般是./bin/Release或者./bin/Debug目录）
 * 运行程序之前，先将CAN1_H接CAN2_H，CAN1_L接CAN2_L，可以直接测试CAN1和CAN2之间的数据收发情况
 */
namespace USB2XXX_CAN_SchTest
{
    class Program
    {
        public static Int32 DevHandle = 0;
        public static Byte CANSendIndex = 0;//CAN1
        public static Byte CANReadIndex = 1;//CAN2
        public static object locker = new object();
        public static bool CANReadMsgFlag = false;
        public static bool CANSendMsgFlag = false;
        public static Int32 SendMsgNum = 0;
        public static void ReadMsgThread()
        {
            while (CANReadMsgFlag)
            {
                USB2CAN.CAN_MSG[] CanMsgBuffer = new USB2CAN.CAN_MSG[1024];
                //申请数据缓冲区
                IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)) * CanMsgBuffer.Length);

                int CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, CANReadIndex, pt, CanMsgBuffer.Length);
                if (CanNum > 0)
                {
                    for (int i = 0; i < CanNum; i++)
                    {
                        CanMsgBuffer[i] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure((IntPtr)(pt + i * Marshal.SizeOf(typeof(USB2CAN.CAN_MSG))), typeof(USB2CAN.CAN_MSG));
                        Console.WriteLine("CanMsg[{0}].ID = {1}", i, CanMsgBuffer[i].ID);
                        Console.WriteLine("CanMsg[{0}].TimeStamp = {1}", i, CanMsgBuffer[i].TimeStamp | ((UInt64)CanMsgBuffer[i].TimeStampHigh << 32));
                        Console.Write("CanMsg[{0}].Data = ", i);
                        for (int j = 0; j < CanMsgBuffer[i].DataLen; j++)
                        {
                            Console.Write("{0:X2} ", CanMsgBuffer[i].Data[j]);
                        }
                        Console.WriteLine("\n");
                    }
                }
                else if (CanNum < 0)
                {
                    Console.WriteLine("Get CAN data error!");
                    break;
                }
                //释放数据缓冲区，必须释放，否则程序运行一段时间后会报内存不足
                Marshal.FreeHGlobal(pt);
                Thread.Sleep(10);
            }
        }
        static void Main(string[] args)
        {
            USB_DEVICE.DEVICE_INFO DevInfo = new USB_DEVICE.DEVICE_INFO();
            Int32[] DevHandles = new Int32[20];
            bool state;
            Int32 DevNum, ret;
            Thread CANReadMsgThread = new Thread(new ThreadStart(ReadMsgThread));
            string dllFilePath = "USB2XXX.dll";
            if (!File.Exists(dllFilePath))
            {
                Console.WriteLine("请先将USB2XXX.dll和libusb-1.0.dll文件复制到exe程序文件输出目录下!");
                Console.WriteLine("dll文件在‘usb2can_lin_pwm_example/sdk/libs/windows’目录下！");
                Console.WriteLine("程序是32位的就复制‘x86’目录下文件，程序是64位的就复制‘x86_64’目录下文件！");
                return;
            }
            //扫描查找设备
            DevNum = USB_DEVICE.USB_ScanDevice(DevHandles);
            if (DevNum <= 0)
            {
                Console.WriteLine("No device connected!");
                return;
            }
            else
            {
                Console.WriteLine("Have {0} device connected!", DevNum);
            }
            DevHandle = DevHandles[0];
            //打开设备
            state = USB_DEVICE.USB_OpenDevice(DevHandle);
            if (!state)
            {
                Console.WriteLine("Open device error!");
                return;
            }
            else
            {
                Console.WriteLine("Open device success!");
            }
            //获取固件信息
            StringBuilder FuncStr = new StringBuilder(256);
            state = USB_DEVICE.DEV_GetDeviceInfo(DevHandle, ref DevInfo, FuncStr);
            if (!state)
            {
                Console.WriteLine("Get device infomation error!");
                return;
            }
            else
            {
                Console.WriteLine("Firmware Info:");
                Console.WriteLine("    Name:" + Encoding.Default.GetString(DevInfo.FirmwareName));
                Console.WriteLine("    Build Date:" + Encoding.Default.GetString(DevInfo.BuildDate));
                Console.WriteLine("    Firmware Version:v{0}.{1}.{2}", (DevInfo.FirmwareVersion >> 24) & 0xFF, (DevInfo.FirmwareVersion >> 16) & 0xFF, DevInfo.FirmwareVersion & 0xFFFF);
                Console.WriteLine("    Hardware Version:v{0}.{1}.{2}", (DevInfo.HardwareVersion >> 24) & 0xFF, (DevInfo.HardwareVersion >> 16) & 0xFF, DevInfo.HardwareVersion & 0xFFFF);
                Console.WriteLine("    Functions:" + DevInfo.Functions.ToString("X8"));
                Console.WriteLine("    Functions String:" + FuncStr);
            }
            //初始化配置CAN
            USB2CAN.CAN_INIT_CONFIG CANConfig = new USB2CAN.CAN_INIT_CONFIG();
            ret = USB2CAN.CAN_GetCANSpeedArg(DevHandle, ref CANConfig, 500000);
            if (ret != USB2CAN.CAN_SUCCESS)
            {
                Console.WriteLine("Get CAN Speed failed!");
                return;
            }
            else
            {
                Console.WriteLine("Get CAN Speed Success!");
            }
            CANConfig.CAN_Mode = 0x80;//正常模式并接入终端电阻，若不使能内部终端电阻，只需要设置为0即可
            ret = USB2CAN.CAN_Init(DevHandle, CANSendIndex, ref CANConfig);
            if (ret != USB2CAN.CAN_SUCCESS)
            {
                Console.WriteLine("Config CAN failed!");
                return;
            }
            else
            {
                Console.WriteLine("Config CAN Success!");
            }
            ret = USB2CAN.CAN_Init(DevHandle, CANReadIndex, ref CANConfig);
            if (ret != USB2CAN.CAN_SUCCESS)
            {
                Console.WriteLine("Config CAN failed!");
                return;
            }
            else
            {
                Console.WriteLine("Config CAN Success!");
            }
            //启动CAN接收
            ret = USB2CAN.CAN_StartGetMsg(DevHandle, CANReadIndex);
            if (ret != USB2CAN.CAN_SUCCESS)
            {
                Console.WriteLine("Start CAN failed!");
                return;
            }
            else
            {
                Console.WriteLine("Start CAN Success!");
            }
            //启动接收数据线程
            CANReadMsgFlag = true;
            CANReadMsgThread.Start();
            //配置CAN调度表
            int CANSchTabNum = 10;
            USB2CAN.CAN_MSG[] CanMsg = new USB2CAN.CAN_MSG[CANSchTabNum];
            for (int i = 0; i < CANSchTabNum; i++)
            {
                CanMsg[i] = new USB2CAN.CAN_MSG();
                CanMsg[i].ExternFlag = 0;
                CanMsg[i].RemoteFlag = 0;
                CanMsg[i].ID = (UInt32)i;
                CanMsg[i].DataLen = 8;
                CanMsg[i].Data = new Byte[CanMsg[i].DataLen];
                for (int j = 0; j < CanMsg[i].DataLen; j++)
                {
                    CanMsg[i].Data[j] = (Byte)j;
                }
            }
            //总共3个调度表，第一个表里面包含3帧数据，第二个调度表包含6帧数据，第三个调度表包含11帧数据
            Byte[] MsgTabNum = new Byte[3]{3,6,11};
            //第一个调度表循环发送数据，第二个调度表循环发送数据，第三个调度表只发送3次
            UInt16[] SendTimes = new UInt16[3]{ 0xFFFF, 0xFFFF, 3 };
            ret = USB2CAN.CAN_SetSchedule(DevHandle, CANSendIndex, CanMsg, MsgTabNum, SendTimes, 3);//配置调度表，该函数耗时可能会比较长，但是只需要执行一次即可
            if (ret == USB2CAN.CAN_SUCCESS)
            {
                Console.WriteLine("Set CAN Schedule Success");
            }else{
                Console.WriteLine("Set CAN Schedule Error ret = {0}", ret);
                return;
            }
            ret = USB2CAN.CAN_StartSchedule(DevHandle, CANSendIndex, 0, 10, 0);//启动第一个调度表,表里面的CAN帧并行发送
            if (ret == USB2CAN.CAN_SUCCESS)
            {
                Console.WriteLine("Start CAN Schedule 1 Success");
            }else{
                Console.WriteLine("Start CAN Schedule 1 Error ret = {0}", ret);
                return;
            }
            Console.ReadLine();
            ret = USB2CAN.CAN_StartSchedule(DevHandle, CANSendIndex, 1, 10, 1);//启动第二个调度表,表里面的CAN帧顺序发送
            if (ret == USB2CAN.CAN_SUCCESS)
            {
                Console.WriteLine("Start CAN Schedule 2 Success");
            }else{
                Console.WriteLine("Start CAN Schedule 2 Error ret = {0}", ret);
                return;
            }
            Console.ReadLine();
            ret = USB2CAN.CAN_StartSchedule(DevHandle, CANSendIndex, 2, 10, 0);//启动第三个调度表，表里面的CAN帧并行发送，每帧只发送3次
            if (ret == USB2CAN.CAN_SUCCESS)
            {
                Console.WriteLine("Start CAN Schedule 3 Success");
            }else{
                Console.WriteLine("Start CAN Schedule 3 Error ret = {0}", ret);
                return;
            }
            Console.ReadLine();
            ret = USB2CAN.CAN_StopSchedule(DevHandle, CANSendIndex);//停止调度表
            if (ret == USB2CAN.CAN_SUCCESS)
            {
                Console.WriteLine("Stop CAN Schedule Success");
            }else{
                Console.WriteLine("Stop CAN Schedule Error ret = {0}", ret);
                return;
            }
            //结束线程
            CANReadMsgFlag = false;
            CANReadMsgThread.Join();
            //停止CAN
            USB2CAN.CAN_StopGetMsg(DevHandle, CANReadIndex);
        }
    }
}
